<?php

namespace SC\Qiniu\Console;

use Illuminate\Console\Command;

use SC\Qiniu\QiniuClient;


class QiniuImage extends Command
{
    protected $signature = 'qiniu:image {src=-} {--key=} {--name=} {--t|template=default}';
    protected $description = 'Manipulate image and Upload to qiniu';

    protected $template = null;

    static function image2data($image, $quality=100)
    {
        \ob_start();
        \imagejpeg($image, NULL, $quality);
        return \ob_get_clean();
    }

    static function getTmpPath($ext='jpg', $prefix='')
    {
        return sprintf("/tmp/%s%s_%d%s", $prefix, now()->format('YmdHis'), random_int(1, 10000), $ext ? '.'.$ext: '');
    }

    function loadData()
    {
        $src = $this->argument('src');

        if ($src == '-') {
            $src = static::getTmpPath();
            $cmd = "pngpaste " . $src;
            $this->info('execute command: '. $cmd);
            exec($cmd);
        }

        return \file_get_contents($src);
    }

    function manipulateImage($data)
    {
        $meta = \getimagesizefromstring($data);
        $image = \imagecreatefromstring($data);

        $image = $this->resizeImage($meta, $image);
        list($compressed, $compressExt) = $this->compressImage($meta, $image);
        if (strlen($data) <= strlen($compressed)) {
            return [$data, explode("/", $meta['mime'])[1]];
        } else {
            return [$compressed, $compressExt];
        }
    }

    function resizeImage($meta, $image)
    {
        $keepRatio = $this->template['keepRatio'];
        $maxWidth = $this->template['maxWidth'];
        $maxHeight = $this->template['maxHeight'];

        list($imgWidth, $imgHeight) = $meta;
        $imgRatio = $imgWidth / $imgHeight;

        $resWidth = $imgWidth;
        $resHeight = $imgHeight;

        if ($maxWidth > 0 && $resWidth > $maxWidth) {
            $resWidth = $maxWidth;
            if ($keepRatio) {
                $resHeight = $resWidth / $imgRatio;
            }
        }

        if ($maxHeight > 0 && $resHeight > $maxHeight) {
            $resHeight = $maxHeight;
            if ($keepRatio) {
                $resWidth = $resHeight * $imgRatio;
            }
        }

        if ($resWidth != $imgWidth || $resHeight != $imgHeight) {
            $this->info(sprintf('resize: (%d, %d) => (%d, %d)', $imgWidth, $imgHeight, (int)$resWidth, (int)$resHeight));

            $tmpPath = static::getTmpPath();
            \file_put_contents($tmpPath, static::image2data($image));
            $cmd = sprintf('sips -z %d %d %s', (int)$resHeight, (int)$resWidth, $tmpPath);
            $this->info('exec compress: '. $cmd);
            exec($cmd);

            return \imagecreatefromjpeg($tmpPath);
        } else {
            $this->info(sprintf('size: (%d, %d)', $imgWidth, $imgHeight));
            return $image;
        }
    }

    function compressImage($meta, $image)
    {
        $quality = $this->template['quality'];
        $this->info('quality = ' . $quality);

        $mime = $meta['mime'];
        if (strpos($mime, 'gif') != FALSE) {
            return [$data, 'gif'];
        } else {
            return [static::image2data($image, $quality), 'jpg'];
        }
    }

    function selectKey($data, $ext)
    {
        $key = $this->option('key');
        if (!empty($key)) {
            return $key;
        }

        $prefix = $this->template['prefix'];
        $name = $this->option('name') ?: md5($data);
        return $prefix . $name . '.' .$ext;
    }

    function upload($key, $data)
    {
        $qiniuClient = new QiniuClient();
        return $qiniuClient->uploadData($key, $data);
    }

    public function handle()
    {
        //init arguments
        $templateName = $this->option('template');
        $this->template = config('qiniu.image.templates.'.$templateName);
        if (is_null($this->template)) {
            $this->error('invalid template config');
            return;
        }

        $data = $this->loadData();
        list($compressed, $ext) = $this->manipulateImage($data);
        $this->info(sprintf("compress: %.2f%% (%d => %d)", (strlen($data) - strlen($compressed)) * 100/strlen($data), strlen($data), strlen($compressed)));

        $key = $this->selectKey($compressed, $ext);

        list($url, $err) = $this->upload($key, $compressed);
        $this->info($url);
        if ($err) {
            $this->info($err->message());
        }
    }
}